﻿using System; 
using Microsoft;
using System.Collections;
using System.Collections.Generic;
using System.Text;
using System.Linq.Expressions;
using System.Dynamic;
using System.Reflection;
using Microsoft.Scripting;
using Microsoft.Scripting.Actions;
using Microsoft.Scripting.Actions.Calls;
using Microsoft.Scripting.Runtime;
using Cjc.Calculation.ExpressionEngine;

namespace Cjc.Calculation.ExpressionEngine.Excel.Runtime.Binding
{
    public class ExcelOverloadResolver : DefaultOverloadResolver
    {
        private readonly Expression _scope;

        public Expression ScopeExpression
        {
            get { return _scope; }
        }

        public ExcelOverloadResolver(ExcelBinder binder, IList<DynamicMetaObject> args, CallSignature signature, Expression scope)
            : this(binder, args, signature, CallTypes.None, scope)
        {
        }

        // method call:
        public ExcelOverloadResolver(ExcelBinder binder, IList<DynamicMetaObject> args, CallSignature signature, CallTypes callType, Expression scope)
            : base(binder, args, signature, callType) {
            _scope = scope;
        }

        private new ExcelBinder Binder
        {
            get
            {
                return (ExcelBinder)base.Binder;
            }
        }

        // Support hidden WorksheetScope parameter to built-in functions
        // Example: Dump(WorksheetScope scope, bool verbose) can be invoked using the expression dump(true)
        // The trick is to specify an ArgBuilder that adds the scope argument automatically behind the scenes
        protected override BitArray MapSpecialParameters(ParameterMapping mapping)
        {
            var infos = mapping.Overload.Parameters;
            BitArray special = base.MapSpecialParameters(mapping);

            if (infos.Count > 0)
            {
                bool normalSeen = false;
                for (int i = 0; i < infos.Count; i++)
                {
                    bool isSpecial = false;
                    if (infos[i].ParameterType == typeof(WorksheetScope) && !normalSeen)
                    {
                        mapping.AddBuilder(new ScopeArgBuilder(infos[i]));
                        isSpecial = true;
                    }
                    else
                    {
                        normalSeen = true;
                    }

                    if (isSpecial)
                    {
                        (special = special ?? new BitArray(infos.Count))[i] = true;
                    }
                }
            }

            return special;
        }
    }
}
